package org.xxpay.pay.channel.suile;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.xxpay.common.unify.AbstractPaymentConfig;
import org.xxpay.common.util.XML;
import org.xxpay.common.util.sign.CertDescriptor;
import org.xxpay.common.util.sign.encrypt.RSA;
import org.xxpay.core.common.constant.PayConstant;
import org.xxpay.core.entity.PayOrder;
import org.xxpay.pay.channel.BasePayNotify;

import java.security.PublicKey;
import java.util.Map;

/**
 * @Package org.xxpay.pay.channel.sand
 * @Class: SandPaymentNotifyService.java
 * @Description:
 * @Author leo
 * @Date 2019/4/11 17:58
 * @Version
 **/
@Component
public class SuilePayNotifyService extends BasePayNotify {
    private final static String logPrefix = "【随乐支付回调】";

    private static CertDescriptor certDescriptor;
    static {
        try {
            certDescriptor = new CertDescriptor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getChannelName() {
        return SuileConfig.CHANNEL_NAME;
    }

    @Override
    public JSONObject doNotify(Object notifyData) {
        JSONObject obj = getRequestParameters(notifyData);
        Map<String, String> requestData = JSONObject.parseObject(obj.toJSONString(), Map.class);
        String data = "";
        for (Map.Entry<String, String> entry : requestData.entrySet()) {
            data += entry.getKey() + entry.getValue();
        }
        // 将字符串的所有空格替换成+字符
        data = data.replaceAll(" ", "+");
        // 将空格、制表符、换行符、回车符替换
        data = data.replaceAll("\\s*|\t|\r|\n",  "");
        _log.info("{}原始参数：{}", logPrefix, data);
        String []  base64 = data.split("\\|");
        JSONObject retObj = buildFailRetObj();
        try {
            String xml = new String(Base64.decodeBase64(base64[0]));
            _log.info("{}xml参数：{}", logPrefix, xml);
            JSONObject origin = XML.xml2Map(xml);
            origin.put("sign", base64[1]);
            origin.put("xml", xml);
            _log.info("{}xml参数：{}", logPrefix, origin.toJSONString());
            if (!verifyPayParams(origin)) {
                retObj.put(PayConstant.RESPONSE_RESULT, SuileConfig.RESPONSE_RESULT_FAIL);
                return retObj;
            }

            PayOrder payOrder = (PayOrder) origin.get("payOrder");
            JSONObject notifyDetailObj = origin.getJSONArray("deductList").getJSONObject(0);
            // 处理订单
            byte payStatus = payOrder.getStatus(); // 0：订单生成，1：支付中，-1：支付失败，2：支付成功，3：业务处理完成，-2：订单过期
            if (payStatus != PayConstant.PAY_STATUS_SUCCESS && payStatus != PayConstant.PAY_STATUS_COMPLETE) {
                String channelOrderId = notifyDetailObj.getString("payOrderId");
                int updatePayOrderRows = rpcCommonService.rpcPayOrderService.updateStatus4Success(payOrder.getPayOrderId(), channelOrderId);
                if (updatePayOrderRows != 1) {
                    _log.error("{}更新支付状态失败,将payOrderId={},更新payStatus={}失败", logPrefix, payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS);
                    retObj.put(PayConstant.RESPONSE_RESULT, "处理订单失败");
                    return retObj;
                }
                _log.error("{}更新支付状态成功,将payOrderId={},更新payStatus={}成功", logPrefix, payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS);
                payOrder.setStatus(PayConstant.PAY_STATUS_SUCCESS);
            }
            // 业务系统后端通知
            baseNotify4MchPay.doNotify(payOrder, true);
            retObj.put(PayConstant.RESPONSE_RESULT, SuileConfig.RESPONSE_RESULT_SUCCESS);
        } catch(Exception e) {
            _log.error("{}参数解析异常", e);
        }
        return retObj;
    }

    private boolean verifyPayParams(JSONObject payContext) {
        // 查询payOrder记录
        String payOrderId = payContext.getString("merchantOrderId");
        PayOrder payOrder = rpcCommonService.rpcPayOrderService.findByPayOrderId(payOrderId);
        if (payOrder == null) {
            _log.error("Can't found payOrder form db. payOrderId={}, ", payOrderId);
            payContext.put("retMsg", "Can't found payOrder");
            return false;
        }

        JSONObject detailObj = payContext.getJSONArray("deductList").getJSONObject(0);

        if(!StringUtils.equals(detailObj.getString("payStatus"), SuileConfig.PAY_STATUS_OK)) {
            payContext.put("retMsg", "notify status not ok");
            return false;
        }

        SuileConfig suileConfig = new SuileConfig(getPayParam(payOrder));

        boolean isVerify = signVerify(payContext.getString("xml"), payContext.getString("sign"), suileConfig);
        if(!isVerify) {
            _log.error("验证签名失败. payOrderId={}", payOrderId);
            payContext.put("retMsg", "验证签名失败");
            return false;
        }

        // 核对金额
        long outPayAmt = detailObj.getLongValue("payAmt");
        long dbPayAmt = payOrder.getAmount().longValue();
        if (dbPayAmt != outPayAmt) {
            _log.error("金额不一致. outPayAmt={},payOrderId={}", outPayAmt, payOrderId);
            payContext.put("retMsg", "金额不一致");
            return false;
        }
        payContext.put("payOrder", payOrder);
        return true;
    }

    public boolean signVerify(String body, String sign, AbstractPaymentConfig config) {
        certDescriptor.initPublicCert(config.getPublicStorePath());
        PublicKey publicKey = certDescriptor.getPublicCert().getPublicKey();
        byte[] bodyMd5Bytes = DigestUtils.md5(body);
        return RSA.verify(bodyMd5Bytes, sign, publicKey);
    }

}
